﻿// controller to handle the folders for the library
angular.module('app.user').controller('UserLibraryFolderController', [
	'$scope', 'libraryService', '$state', 'dataService', '$location', '$interpolate', 'libraryMediator', 'notify',
	function ($scope, libraryService, $state, dataService, $location, $interpolate, libraryMediator, notify) {
		var instance = this;
		// set the reference in the mediator
		libraryMediator.setFolderController(instance);
		// intialize the folder model
		$scope.folderModel = {
			newFolderName: 'New Folder',
			removeFolderName: '',
			createNewFolder: false,
			removeFolder: false,
			folders: [],
			moveFolder: [],
			isLoading: true
		};
		// reference the current folder to the parent scope's model.current folder and the setter to the function
		Object.defineProperty($scope.folderModel, "currentFolder", {
			get: function () { return $scope.model.currentFolder; },
			set: function (newValue) { $scope.setCurrentFolder(newValue); },
			enumerable: true,
			configurable: true
		});

		// show Create Folder 
		$scope.showCreateNewFolder = function () {
			// default the name to 'new folder'
			$scope.folderModel.newFolderName = 'New Folder';
			$scope.folderModel.createNewFolder = true;
		};
		// cancel creating a new folder
		$scope.cancelCreateNewFolder = function () {
			$scope.folderModel.createNewFolder = false;
		};

		// show Remove Folder
		$scope.showRemoveFolder = function () {
			// set the remove folder name to the current folder's name
			$scope.folderModel.removeFolderName = $scope.folderModel.currentFolder.Name;
			$scope.folderModel.removeFolder = true;
		};
		// cancel remove folder process
		$scope.cancelRemoveFolder = function () {
			$scope.folderModel.removeFolder = false;
		};

		// show Move Folder
		$scope.showMoveFolder = function () {
			// set the folder to be moved and the display name
			$scope.folderModel.moveFolder = $scope.folderModel.currentFolder;
			$scope.folderModel.moveFolderName = $scope.folderModel.moveFolder.Name;
			$scope.folderModel.moveCurrentFolder = true;
		};
		// cancel move folder
		$scope.cancelMoveFolder = function () {
			$scope.folderModel.moveCurrentFolder = false;
		};
		// handle create folder response
		this.handleCreateNewFolderResponse = function (response) {
			// show success message or error message
			if (response.data.Successful) {
				notify.success('Folder was created');
			}
			else {
				notify.error(response.data.Message);
			}
			// if content was returned
			if (response.data.Content !== null && response.data.Content !== undefined) {
				// prepare the new folder
				prepFolder($scope.folderModel.currentFolder.path + $scope.folderModel.currentFolder.Name + '/', response.data.Content);
				// if the current folder does not have subfolders, initialize the array
				if ($scope.folderModel.currentFolder.Folders === null || $scope.folderModel.currentFolder.Folders === undefined) {
					$scope.folderModel.currentFolder.Folders = [];
				}
				// add the new folder to the subfolder's array
				$scope.folderModel.currentFolder.Folders.push(response.data.Content);
			}
			// no londer creating a new folder
			$scope.folderModel.createNewFolder = false;
		};
		// handle the remove folder response
		this.handleRemoveFolderResponse = function (response) {
			if (response.data.Successful) {
				// notify the move was successful
				notify.success('Folder was removed');
				// find the parent folder from the list of folders and the path
				var findFolder = instance.FindParentFolderByPath($scope.folderModel.folders, $scope.folderModel.currentFolder.path);
				// find the current folder in the sub folders collection of the parent folder
				var spliceIndex = instance.findFolderIndex(findFolder.Folders, $scope.folderModel.currentFolder.Name);
				findFolder.Folders.splice(spliceIndex, 1);
				$scope.selectFolder(findFolder);
			}
			else {
				// notify the user of the error
				notify.error(response.data.Message);
			}
			// cancel moving the folder
			$scope.folderModel.removeFolder = false;
		};
		// handle the folder rename resposne
		this.handleRenameFolderResponse = function (response) {
			// if successful
			if (response.data.Successful) {
				// notify the user
				notify.success('Folder was renamed');
				// set the new name just in case it was changed by the resolver
				$scope.folderModel.currentFolder.Name = response.data.Content.Name;
				// set the "new name" to the folder's name for the next rename
				$scope.folderModel.currentFolder.newName = response.data.Content.Name;
				// find the current folder in the path
				var foundFolder = instance.FindCurrentFolderByPath($scope.folderModel.folders, $scope.folderModel.currentFolder.path, $scope.folderModel.currentFolder.Name);
				// loop through the sub folders
				for (var index in foundFolder.Folders) {
					// find the current folder's name in the path and replace it with the new name
					if (foundFolder.Folders[index].Name !== null) {
						// split the path using the slash
						var childPath = foundFolder.Folders[index].path;
						var splitPath = childPath.split("/");
						splitPath.splice(splitPath.length - 2, 1, foundFolder.Name);
						// build the new path
						var newPath = "";
						for (var x in splitPath) {
							newPath += splitPath[x];

							if (x < splitPath.length - 1) {
								newPath += "/";
							}
						}
						// set the path on the folder
						foundFolder.Folders[index].path = newPath;
					}
				}
			}
			else {
				// notify the user of the error
				notify.error(response.data.Message);
			}
		};
		// handle the move folder response
		this.handleMoveFolderResponse = function (response) {
			if (response.data.Successful) {
				// notify the user of the successful move
				notify.success('Folder was moved');
				//remove folder being moved
				var previousParentFolder = instance.FindParentFolderByPath($scope.folderModel.folders, $scope.folderModel.moveFolder.path);
				var spliceIndex = instance.findFolderIndex(previousParentFolder.Folders, $scope.folderModel.moveFolder.Name);
				previousParentFolder.Folders.splice(spliceIndex, 1);

				// set the correct path
				changeFolderPath($scope.folderModel.moveFolder, $scope.folderModel.currentFolder.path +
					$scope.folderModel.currentFolder.Name + '/');
				// add the folder to the selected folder subfolder list
				$scope.folderModel.currentFolder.Folders.push($scope.folderModel.moveFolder);
				$scope.folderModel.moveFolder = null;
			}
			else {
				// notify the user of the error
				notify.error(response.data.Message);
			}
			// stop the folder move process
			$scope.folderModel.moveCurrentFolder = false;
		};
		// submit the create new folder request to the server
		$scope.submitCreateNewFolder = function () {
			dataService.upload('Folder', { Name: $scope.folderModel.newFolderName, ParentFolderId: $scope.folderModel.currentFolder.Id })
				.then(instance.handleCreateNewFolderResponse);
		};
		// submit the remove folder request to the server
		$scope.submitRemoveFolder = function () {
			dataService.upload('Folder', { Id: $scope.folderModel.currentFolder.Id, IsDeleted: true })
			.then(instance.handleRemoveFolderResponse);
		};
		// submit the move folder request to the server
		$scope.submitMoveFolder = function () {
			dataService.upload('Folder', { Id: $scope.folderModel.moveFolder.Id, ParentFolderId: $scope.folderModel.currentFolder.Id })
			.then(instance.handleMoveFolderResponse);

		};
		// toggle the folder node open or closed
		$scope.toggleNode = function (node) {
			node.toggle();
		}
		// select a specific folder
		$scope.selectFolder = function (folder) {
			// get the currently selected folder
			var current = $scope.folderModel.currentFolder;
			// if moving an image, set the "selected" folder as the destination folder
			if ($scope.model.isMovingImage) {
				$scope.setImageDestinationFolder(folder);
			}
			else {
				// if a current folder is selected, then unselect
				if (current !== null && current !== undefined) {
					current.unselect();
				}
				// if not actually selecting a folder (viewing favorites)
				// reset the folder to null and id to -1
				if (folder === null || folder === undefined) {
					$scope.folderModel.currentFolder = null;
					$scope.setFolderId(-1);
				}
				else {
					// select the new folder
					// set the current folder and folder Id
					folder.select();
					$scope.folderModel.currentFolder = folder;
					$scope.setFolderId(folder.Id);
					// set the new browser URL
					$location.path($interpolate('user/{{model.params.userId}}/view/folder/{{node.Id}}')({ model: $scope.model, node: folder }));
				}
			}
		}
		// function to prepare a folder for use in the folder tree
		var prepFolder = function (path, folder) {
			// initialze new properties
			folder.path = path;
			folder.selected = false;
			folder.collapsed = true;
			folder.nodeClass = ['collapsed-node'];
			folder.imgsrc = 'folder';
			folder.newName = folder.Name;
			// toggle between open and collapsed states
			folder.toggle = function () {
				// change the collapsed state
				folder.collapsed = !folder.collapsed;
				// change the class
				folder.nodeClass = [(folder.collapsed ? 'collapsed-node' : 'expanded-node')];
				// change the icon
				folder.imgsrc = (folder.collapsed ? 'folder' : 'folder_o') + (folder.selected ? '_s' : '');
			};
			// unselect the folder
			folder.unselect = function () {
				// selected false
				folder.selected = false;
				// change the class
				folder.nodeClass = [(folder.collapsed ? 'collapsed-node' : 'expanded-node')];
				// change the icon
				folder.imgsrc = 'folder';
			};
			// select the folder
			folder.select = function () {
				// expand the folder
				folder.collapsed = false;
				// selected
				folder.selected = true;
				// set class and icon
				folder.nodeClass = ['selected-node'];
				folder.imgsrc = 'folder_o_s';
			};
		},
		// change the folder's path to the new path
		changeFolderPath = function (folder, newPath) {
			//set the new path
			folder.path = newPath;
			// if contains sub folders
			if (folder.Folders != null &&
				folder.Folders != undefined &&
				folder.Folders.length > 0) {
				// change the subfolder's path
				var subPath = newPath + folder.Name + '/';
				angular.forEach(folder.Folders, function (subFolder) {
					// cascade the change to subfolders
					changeFolderPath(subFolder, subPath);
				});
			}
		},
		// collapse all of the folders and expand the folders up the chain of the selected folder
		collapseAllFolders = function (parentFolder, parentPath, folders) {
			// get the current folder id
			var fid = $scope.getFolderId();
			if (folders == null || folders == undefined || folders.length < 1) {
				return;
			}

			var folderWasExpanded = false;
			// for each of the passed folders
			angular.forEach(folders, function (folder) {
				// prepare the folder
				prepFolder(parentPath, folder);
				// if the folder is the selected folder from the parameters of the url
				if (folder.Id.toString() === fid) {
					// select the folder
					$scope.selectFolder(folder);
					// signal that a folder was expanded
					folderWasExpanded = true;
				}
				// check the folders underneath this folder
				collapseAllFolders(folder, parentPath + folder.Name + '/', folder.Folders);
			});
			// if a folder was expanded and the parent folder is not null, expand the parent folder too
			if (folderWasExpanded && parentFolder !== null && parentFolder !== undefined) {
				parentFolder.toggle();
			}
		};
		// find a folder within the given array by its name
		this.findFolder = function (folderArray, folderName) {
			// for all folders
			for (var index in folderArray) {
				// if the names match, return the folder
				if (folderArray[index].Name === folderName) {
					return folderArray[index];
				}
			}
			// return null because the folder was not found
			return null;
		};

		// find the index for a folder based on the passed name
		this.findFolderIndex = function (folderArray, folderName) {
			for (var index in folderArray) {
				// for each folder, if the name matches return the index
				if (folderArray[index].Name === folderName) {
					return index;
				}
			}
			// return null because the folder was not found
			return null;
		};

		// the the parent folder of folder by its path
		this.FindParentFolderByPath = function (folderList, path) {
			// split the path
			var folderNames = path.split('/');
			index = 0;
			var foundFolder = null,
				currentList = folderList;
			// loop through each section of the patth
			while (index < folderNames.length - 1) {
				// find the folder one level down
				foundFolder = instance.findFolder(currentList, folderNames[index]);
				// if not found then the path is wrong and esacpe
				if (foundFolder === null) {
					return null;
					// not found 
				}
				// fount the folder so set the list to the next level down
				currentList = foundFolder.Folders;
				// go to the next level in the path
				index++;
			}
			// return the found folder
			return foundFolder;
		};
		// find a folder based on its path
		this.FindCurrentFolderByPath = function (folderList, path, currentFolderName) {
			// split the path
			var folderNames = path.split('/');
			// splice the folder names and add the current folder name
			folderNames.splice(folderNames.length - 1, 1, currentFolderName);

			index = 0;
			var foundFolder = null,
				currentList = folderList;
			while (index < folderNames.length) {
				// find the folder one level down
				foundFolder = instance.findFolder(currentList, folderNames[index]);
				// if not found then the path is invalid and return a null
				if (foundFolder === null) {
					return null;
					// not found 
				}
				// found, so set the next level down and increment the index
				currentList = foundFolder.Folders;
				index++;
			}
			// return the found folder
			return foundFolder;
		};
		// handle the get folders response
		this.handleGetFoldersResponse = function (response) {
			$scope.folderModel.isLoading = false;
			// if successful
			if (response.data.Successful && response.data.Content.length > 0) {
				// collapse and prepare the folders
				collapseAllFolders(null, '', response.data.Content);

				// if no folder was selected, select the first folder in the response
				if ($scope.folderModel.currentFolder === null || $scope.folderModel.currentFolder === undefined) {
					$scope.selectFolder(response.data.Content[0]);
				}
				// set the folders to the content of the response
				$scope.folderModel.folders = response.data.Content;
			}
			else {
				// should always return at least one but since none, set to empty
				$scope.folderModel.folders = [];
			}
		};

		// load the folder data
		this.loadData = function () {
			// if the user isn't defined, don't load
			if ($scope.model.user === null || $scope.model.user === undefined) {
				return;
			}
			// get the folders from the library service
			libraryService.getFolders($scope.model.user.Id).then(instance.handleGetFoldersResponse);
		};
		// if the model user has been set, then load the folders
		if ($scope.model.user !== null && $scope.model.user !== undefined) {
			this.loadData();
		}
		else {
			// otherwise, wait for the model user to be populated
			$scope.$watch('model.user', function () {
				instance.loadData();
			});
		}
	}]);